package com.view.cn.mvprxjava.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.view.cn.mvprxjava.R;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义九宫格解锁
 * Created by Zengxiaoping on 2016/12/5.
 */

public class LockView extends View {

	public static final int ERROR_POINT_LENGHT_ONE = -999;             //只绘制一个点
	public static final int ERROR_POINT_LENGHT_NOT_ENOUGH = -998;      //绘制点长度小于4

	//九宫格的数据
	private Point[][] mPoints = new Point[3][3];
	//是否已经初始化、是否选中九宫格的点、是否移动到了不是九宫格点上
	private boolean mIsInit, mIsSlectPoint, mMoveNoPoint = false;
	//宽高，偏移量
	private int mWidth, mHeight, mOffWidth, mOffHeight;
	//画笔
	private Paint mPaint;
	//图片
	private Bitmap mBitmapPointNomal, mBitmapPointError, mBitmapPointPressed;

	//(图片)圆的半径
	private float mRadiu;
	//记录经过的点的集合
	private List<Point> mPointList;
	//手指触摸点的坐标
	private float mEventX, mEventY;

	public LockView(Context context) {
		super(context);
	}

	public LockView(Context context, AttributeSet attrs) {
		super(context, attrs);
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		mWidth = w;
		mHeight = h;
		super.onSizeChanged(w, h, oldw, oldh);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (!mIsInit) {
			mIsInit = true;
			//初始化图案的点
			initPoint();
		}
		// 绘制点到画布
		canvusPoint(canvas);
		//绘制九宫格的点的连线
		if (mPointList.size() > 0) {

			//绘制九宫格的坐标点
			Point pointA = mPointList.get(0);
			//路径
			Path path = new Path();
			//先移动开始位置到第一个触摸点的位置
			path.moveTo(pointA.x, pointA.y);
			for (int i = 0; i < mPointList.size(); i++) {
				Point pointB = mPointList.get(i);
				lineCanvas(pointA, pointB, canvas, path);
				pointA = pointB;
			}
			//如果连线时，收拾超出了九宫格范围，或者不在九宫格点上也需要画出来那根线
			if (mMoveNoPoint) {
				lineCanvas(pointA, new Point(mEventX, mEventY), canvas, path);
			}
		}
	}

	/**
	 * 划线(连接九宫格两点的连线)
	 *
	 * @param pointA
	 * @param pointB
	 * @param canvas
	 */
	private void lineCanvas(Point pointA, Point pointB, Canvas canvas, Path path) {
		mPaint.setStrokeWidth(5);
		mPaint.setStyle(Paint.Style.STROKE);
		path.lineTo(pointB.x, pointB.y);
		canvas.drawPath(path, mPaint);
	}

	private void initPoint() {
		//判断屏幕横竖屏状态
		if (mWidth > mHeight) {//横屏状态
			mOffWidth = (mWidth - mHeight) / 2;
			mWidth = mHeight;
		} else {//竖屏
			mOffHeight = (mHeight - mWidth) / 2;
			mHeight = mWidth;
		}

		/**
		 * 计算点的位置，假如是800*1280横屏，那么各个点坐标为
		 * mOffWidth=240;    mWidth=800;
		 * mPoints[0][0]:440,200
		 * mPoints[0][1]:640,200
		 * mPoints[0][2]:840,200
		 * mPoints[1][0]:440,400
		 * mPoints[1][1]:640,400
		 * mPoints[1][2]:840,400
		 * mPoints[2][0]:440,600
		 * mPoints[2][1]:640,600
		 * mPoints[2][2]:840,600
		 */
		mPoints[0][0] = new Point(mOffWidth + mWidth / 4, mOffHeight + mWidth / 4);
		mPoints[0][1] = new Point(mOffWidth + mWidth / 2, mOffHeight + mWidth / 4);
		mPoints[0][2] = new Point(mOffWidth + mWidth - mWidth / 4, mOffHeight + mWidth / 4);
		mPoints[1][0] = new Point(mOffWidth + mWidth / 4, mOffHeight + mWidth / 2);
		mPoints[1][1] = new Point(mOffWidth + mWidth / 2, mOffHeight + mWidth / 2);
		mPoints[1][2] = new Point(mOffWidth + mWidth - mWidth / 4, mOffHeight + mWidth / 2);
		mPoints[2][0] = new Point(mOffWidth + mWidth / 4, mOffHeight + mWidth - mWidth / 4);
		mPoints[2][1] = new Point(mOffWidth + mWidth / 2, mOffHeight + mWidth - mWidth / 4);
		mPoints[2][2] = new Point(mOffWidth + mWidth - mWidth / 4, mOffHeight + mWidth - mWidth / 4);

		//添加图片资源
		mBitmapPointNomal = BitmapFactory.decodeResource(getResources(), R.mipmap.point_normal);
		mBitmapPointError = BitmapFactory.decodeResource(getResources(), R.mipmap.point_error);
		mBitmapPointPressed = BitmapFactory.decodeResource(getResources(), R.mipmap.point_pressed);

		//得到图片半径
		mRadiu = mBitmapPointNomal.getWidth() / 2;

		//设置密码
		int index = 1;
		for (Point[] points : mPoints) {
			for (Point point : points) {
				point.index = index;
				index++;
			}
		}

		mPointList = new ArrayList<>();
	}


	private void canvusPoint(Canvas canvas) {
		for (int i = 0; i < mPoints.length; i++) {
			for (int j = 0; j < mPoints[i].length; j++) {
				Point point = mPoints[i][j];
				switch (point.state) {
					case Point.STATE_PRESSED:   //选中状态
						canvas.drawBitmap(mBitmapPointPressed, point.x - mBitmapPointPressed.getWidth() / 2, point.y - mBitmapPointPressed.getWidth() / 2, mPaint);
						break;
					case Point.STATE_ERROR:     //错误状态
						canvas.drawBitmap(mBitmapPointError, point.x - mBitmapPointError.getWidth() / 2, point.y - mBitmapPointError.getWidth() / 2, mPaint);
						break;
					case Point.STATE_NOMAL:     //正常状态
					default:
//						mPaint.setColor(Color.GREEN);
						// 调整画布的位置，因为在点的右下边开始画的图案，图案的中心并没有和点对齐，
						// 将图案向上和左偏移图案的半径（pointNormal.getwidth()/2）
						canvas.drawBitmap(mBitmapPointNomal, point.x - mBitmapPointNomal.getWidth() / 2, point.y - mBitmapPointNomal.getWidth() / 2, mPaint);
						break;
				}
			}
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		mEventX = event.getX();
		mEventY = event.getY();
		Point point = null;
		switch (event.getAction()) {
			//按下
			case MotionEvent.ACTION_DOWN:
				//每次按下都要重置
				resetPointList();
				point = checkSelectPoitn(mEventX, mEventY);
				if (point != null) {
					point.state = Point.STATE_PRESSED;
					mIsSlectPoint = true;
				}
				break;
			//移动
			case MotionEvent.ACTION_MOVE:
				if (mIsSlectPoint) {
					point = checkSelectPoitn(mEventX, mEventY);
					if (point == null) {
						//如果重复,不添加到集合中，但绘制并没有结束，添加标记,此标记在重复选择时为true，在九宫格范围外为true
						mMoveNoPoint = true;
					} else {
						if (crossPoint(point)) {
							mMoveNoPoint = true;
						} else {
							point.state = Point.STATE_PRESSED;
							mPointList.add(point);
						}
					}
				}
				break;
			//离开
			case MotionEvent.ACTION_UP:
				mMoveNoPoint = false;
				if (mPointList.size() == 1) {
					resetPointList();
					//失败回调
					if (mCanvusFinishListener != null) {
						mCanvusFinishListener.failed(ERROR_POINT_LENGHT_ONE);
					}
				} else if (mPointList.size() < 4) {
					setErrorPoint();
					//失败回调
					if (mCanvusFinishListener != null) {
						mCanvusFinishListener.failed(ERROR_POINT_LENGHT_NOT_ENOUGH);
					}
				} else {
					//拼接密码
					StringBuilder stringBuilder = new StringBuilder();
					for (Point points : mPointList) {
						stringBuilder.append(points.index);
					}
					//完成回调
					if (mCanvusFinishListener != null) {
						mCanvusFinishListener.finish(stringBuilder.toString());
					}
				}
				break;
		}
		//每次都刷新view
		invalidate();
		return true;
	}

	/**
	 * 交叉点的判断(集合中是否包含此点)
	 *
	 * @return （连线中）是否已经存在该点
	 */
	private boolean crossPoint(Point point) {
		return mPointList.contains(point);
	}

	/**
	 * 重置
	 */
	private void resetPointList() {
		for (int i = 0; i < mPointList.size(); i++) {
			Point point = mPointList.get(i);
			point.state = Point.STATE_NOMAL;
		}
		mPointList.clear();
	}

	/**
	 * 设置成错误的状态
	 */
	private void setErrorPoint() {
		for (Point point : mPointList) {
			point.state = Point.STATE_ERROR;
		}
	}

	/**
	 * 判断按下的地方存在的点  存在就返回
	 *
	 * @param eventX 触摸X坐标
	 * @param eventY 触摸Y坐标
	 * @return 触摸的点
	 */
	private Point checkSelectPoitn(float eventX, float eventY) {
		for (int i = 0; i < mPoints.length; i++) {
			for (int j = 0; j < mPoints.length; j++) {
				Point point = mPoints[i][j];
				if (Point.isCoincide(mRadiu, point.x, point.y, eventX, eventY)) {
					return point;
				}
			}
		}
		return null;
	}

	/**
	 * 提供接口，用于绘制图形完成或者失败的回调
	 */
	public interface CanvusFinishListener {
		void finish(String password);   //成功，返回密码

		void failed(int state);         //失败，返回状态码
	}

	private CanvusFinishListener mCanvusFinishListener;

	public void setCanvusFinishListener(CanvusFinishListener canvusFinishListener) {
		if (canvusFinishListener != null) {
			mCanvusFinishListener = canvusFinishListener;
		}
	}

	//九宫格的点
	public static class Point {

		//正常状态、选中状态、错误状态
		public static final int STATE_NOMAL = 0;
		public static final int STATE_PRESSED = 1;
		public static final int STATE_ERROR = 2;

		public float x, y;
		public int index;
		public int state;

		public Point() {
		}

		public Point(float x, float y) {
			this.x = x;
			this.y = y;
		}

		/**
		 * 判断点击的点是否在图片的范围内
		 *
		 * @param radius 图片半径
		 * @param pointX 图片点的x坐标
		 * @param pointY 图片点的Y坐标
		 * @param eventX 触摸点的X坐标
		 * @param eventY 触摸点的Y坐标
		 * @return 是否在团的范围内
		 */
		public static boolean isCoincide(float radius, float pointX, float pointY, float eventX, float eventY) {
			//乘以2 这样的话就算经过的的图形点附近一点点也能连接上
			return Math.sqrt((pointX - eventX) * (pointX - eventX) + (pointY - eventY) * (pointY - eventY)) < radius * 2;
		}
	}
}
